<?php


namespace App\Service\Cooperative;


use App\Constants\ErrorCode;
use App\Constants\Model\ConfigOther;
use App\Dao\AdminUserDao;
use App\Dao\CooperativeMenuDao;
use App\Dao\CooperativeRoleDao;
use App\Model\Cooperative;
use App\Dao\CooperativeDao;
use App\Dao\CooperativeUserDao;
use App\Exception\BusinessException;
use App\Model\CooperativeMenu;
use App\Model\CooperativeRole;
use App\Model\CooperativeUser;
use App\Utils\Casbin;
use App\Utils\Jwt;
use App\Utils\Log;
use App\Utils\Notice\AminBingApplets;
use App\Utils\Notice\Sender;
use App\Utils\SMS;
use App\Utils\Upload\Server;
use App\Utils\Wechat\OpenPlatform\OpenPlatform;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use function EasyWeChat\Kernel\Support\str_random;

class CooperativeService extends BaseService
{

    /**
     * @Inject()
     * @var CooperativeDao
     */
    protected $cooperativeDao;

    /**
     * @Inject()
     * @var CooperativeMenuDao
     */
    protected $cooperativeMenuDao;

    /**
     * @Inject()
     * @var CooperativeRoleDao
     */
    protected $cooperativeRoleDao;

    /**
     * @Inject()
     * @var CooperativeUserDao
     */
    protected $cooperativeUserDao;

    /**
     * @Inject()
     * @var AdminUserDao
     */
    protected $adminUserDao;

    /**
     * @Inject()
     * @var Server
     */
    public $server;

    /**
     * @var Casbin|mixed
     */
    protected $casbinInstance;

    public function __construct()
    {
        $this->casbinInstance = make(Casbin::class, [config('casbin.cooperative')]);
    }

    /**
     * @param string $phone
     * @param string $code
     * @return string
     * @throws \Exception
     */
    public function register(string $phone, string $code): array
    {
        switch (env('APP_ENV')) {
            case 'local':
                break;
            case 'dev':
                break;
            default:
                if (!di(SMS::class)->checkCaptcha($phone, $code)) {
                    throw new BusinessException(ErrorCode::SMS_CAPTCHA_UNEQUAL);
                }
        }

        $cooperativeUser = $this->cooperativeUserDao->first(['mobile' => $phone]);
        if (!$cooperativeUser) {
            $cooperativeUser = $this->initCooperative($phone);
        }
        /** @var Cooperative $cooperative */
        $cooperative = $this->cooperativeDao->where(['id' => $cooperativeUser->cooperative_id])->first();

        if($cooperative->status == \App\Constants\Model\Cooperative::STATUS_BLOCKED){
            throw new BusinessException(ErrorCode::COOPERATIVE_DISABLE);
        }

        $roleId = $this->casbinInstance->getRolesByUser($cooperativeUser->id)[0];

        /** @var CooperativeRole $role */
        $role = $this->cooperativeRoleDao->firstOrThrow(['id' => $roleId]);
        $menus = $role->cooperativeMenus;
//        $start = date('Y-md H:i:s');
        $tree = $this->cooperativeMenuDao->tree($menus);
//        dump([$start,date('Y-md H:i:s')]);

        return [
            'token' => Jwt::token(['id' => $cooperativeUser->id], 'jwt.cooperative'),
            'cooperative_user' => $cooperativeUser->toArray(),
            'cooperative' => [
                'contact' => $cooperative->contact,
                'phone' => $cooperative->phone,
                'domain' => $cooperative->domain,
                'nickname' => $cooperative->nickname,
                'wx_merchant_secret' => $cooperative->wx_merchant_secret,
                'wx_merchant_code' => $cooperative->wx_merchant_code,
                'wx_cert' => $cooperative->wx_cert,
                'audit_status' => $cooperative->audit_status,
                'audit_message' => $cooperative->audit_message,
                'province' => $cooperative->province,
                'city' => $cooperative->city,

            ],
            'menu' => $tree
        ];
    }

    /**
     * 绑定微信小程序
     * @param array $data
     * @return Cooperative
     */
    public function bindWxMerchant(array $data)
    {
        $cooperativeUser = $this->user();
        $cooperative = $cooperativeUser->cooperative;

        //TODO 校验 wx_merchant_secret wx_merchant_cde wx_cert 有效性
        $cooperative->wx_merchant_secret = $data['wx_merchant_secret'];
        $cooperative->wx_merchant_code = $data['wx_merchant_code'];
        $cooperative->wx_cert = $data['wx_cert'];
        $cooperative->bind_wx_merchant = \App\Constants\Model\Cooperative::BIND_WX_MERCHANT_NO;

        $cooperative->province = $data['province'];
        $cooperative->city = $data['city'];
        $cooperative->nickname = $data['nickname'];
        $cooperative->logo = $data['logo'];
        $cooperative->audit_status = \App\Constants\Model\Cooperative::AUDIT_STATUS_WAIT;

        $cooperative->save();

        //通知母公司后台（所有人）
        $adminUser = $this->adminUserDao->where(['deleted_at'=>null])->pluck('id')->toArray();
        Sender::send($adminUser, new AminBingApplets());

        return $cooperative;
    }

    /**
     * 获取小程序授权信息
     * @param int $cooperativeId
     * @param string $authCode
     * @return int
     * @throws \Exception
     */
    public function bindWxMp(int $cooperativeId, string $authCode)
    {
        /** @var Cooperative $cooperative */
        $cooperative = $this->cooperativeDao->first(['id' => $cooperativeId]);

        $openPlatform = di(OpenPlatform::class);

        $authorizer = $openPlatform->handleAuthorize($authCode);
        $appID = $authorizer['authorization_info']['authorizer_appid'];
        if ($this->cooperativeDao->first(['wx_mp_appid' => $appID])) {
            return ErrorCode::REPETITION_BIND;
        }
        $cooperative->wx_mp_appid = $authorizer['authorization_info']['authorizer_appid'];
        $cooperative->nickname = $authorizer['authorization_info']['authorizer_appid'];
        $cooperative->wx_mp_name = '';
        $cooperative->wx_mp_secret = '';
        $cooperative->bind_mp = \App\Constants\Model\Cooperative::BIND_MP_YES;
        if ($cooperative->save()) {
            return \App\Constants\Model\Cooperative::BIND_MP_YES;
        }
        return \App\Constants\Model\Cooperative::BIND_MP_NO;
    }

    /**
     * 生成小程序授权url
     * @return string
     */
    public function preAuthUrl()
    {
        $callbackUrl = env('PRE_AUTH_URL');
        $callbackUrl = $callbackUrl . '/' . $this->user()->cooperative_id;
        return di(OpenPlatform::class)->preAuthUrl($callbackUrl);
    }

    /**
     * 初始化合作商
     * @param string $phone
     * @return CooperativeUser
     * @throws \Exception
     */
    public function initCooperative(string $phone): CooperativeUser
    {
        //查看默认权限是否有变化
        Db::beginTransaction();
        try {
            /**
             * 创建运营商信息
             * @var $cooperative \App\Model\Cooperative
             */
            $cooperative = new Cooperative();

            //TODO 随机生成8位目录
            $cooperative->domain = str_random(8);
            $cooperative->phone = $phone;
            $cooperative->contact = $phone;
            $cooperative->logo = '';
            $cooperative->nickname = '';
            $cooperative->status = \App\Constants\Model\Cooperative::STATUS_UNBLOCK;
            $cooperative->bind_mp = \App\Constants\Model\Cooperative::BIND_MP_NO;
            $cooperative->bind_wx_merchant = \App\Constants\Model\Cooperative::BIND_WX_MERCHANT_NO;
            $cooperative->save();

            //初始化默认配置
            $configOthers = [];
            foreach (ConfigOther::TEMPLATES as $name=>$template) {
                $configOthers[] = new \App\Model\ConfigOther([
                    'name' =>$name,
                    'val' => $template['default_value']
                ]);
            }
            $cooperative->configOthers()->saveMany($configOthers);

            //创建默认权限
            $defaultMenuConfigIds = array_unique(config('menus.default_cooperative_role.menus'));
            $defaultMenus = [];
            foreach ($defaultMenuConfigIds as $defaultMenuConfigId) {
                $defaultMenus[] = new CooperativeMenu(['menu_config_id' => $defaultMenuConfigId]);
            }
            $cooperativeMenus = $cooperative->cooperativeMenus()->saveMany($defaultMenus);

            /**
             * 创建默认角色并关联权限
             * @var $cooperativeRole CooperativeRole
             */
            $defaultRoleConfig = [
                'name' => config('menus.default_cooperative_role.name'),
                'remark' => config('menus.default_cooperative_role.remark')
            ];;
            $cooperativeRole = new CooperativeRole($defaultRoleConfig);
            $cooperativeRole->cooperative_id = $cooperative->id;
            $cooperativeRole->save();
            $cooperativeMenuIds = array_map(function ($cooperativeMenu) {
                return $cooperativeMenu->id;
            }, $cooperativeMenus);

            $cooperativeRole->cooperativeMenus()->sync($cooperativeMenuIds);
            $menuApis = [];
            foreach ($cooperativeMenus as $cooperativeMenu) {
                /** @var $cooperativeMenu CooperativeMenu */
                if ($cooperativeMenu->isApi()) {
                    $menuApis[] = $cooperativeMenu->api;
                }
            }

            $this->casbinInstance->setPermissionsForRole($cooperativeRole->id, array_unique($menuApis));

            /**
             * 创建默认运营人员并关联角色
             * @var $cooperativeUser CooperativeUser
             */
            $cooperativeUser = new CooperativeUser();
            $cooperativeUser->is_manager = \App\Constants\Model\CooperativeUser::IS_MANAGER_YES;
            $cooperativeUser->cooperative_id = $cooperative->id;
            $cooperativeUser->mobile = $phone;
            $cooperativeUser->contact = $phone;
            $cooperativeUser->username = '';
            $cooperativeUser->password = password_hash('', PASSWORD_BCRYPT);
            $cooperativeUser->save();
            $this->casbinInstance->setRolesForUser($cooperativeUser->id, [$cooperativeRole->id]);
            Db::commit();
        } catch (\Exception $exception) {
            Db::rollBack();
            Log::get()->error($exception->getMessage(), ['phone' => $phone]);
            throw $exception;
        }
        return $cooperativeUser;
    }

    /**
     * 上传api证书
     * @param $data
     * @return mixed
     */
    public function uploadApi($data)
    {
        $res = $this->server->upload($data['upload_file'],
            [
                'allowMine' => ['text/plain','application/octet-stream'],
                'allowSuffix' => ['pem','pfx','key'],
            ]);
        $ret = [
            'id' => $res->getId(),
            'file_url' => $res->getImage()
        ];

        return $ret;
    }

    /**
     * 获取合作商信息
     * @return \Hyperf\Database\Model\Builder|\Hyperf\Database\Model\Model|object|null
     */
    public function cooperativeInfo()
    {
        $field = ['id','contact','phone','domain','nickname',
                  'wx_mp_name','wx_mp_appid','wx_mp_secret','wx_merchant_secret',
                  'wx_merchant_code','wx_cert','status','bind_mp','bind_wx_merchant','audit_status',
                  'audit_message','wx_mp_audit_message','province','city','area','logo'];
        return $this->cooperativeDao->first(['id'=>$this->user()->cooperative_id],$field);
    }
}